package com.gitee.wsl.serialization.json

import com.gitee.wsl.serialization.json.context.JsonContext.Default.decode
import com.gitee.wsl.serialization.json.context.JsonContext.Default.decodeOrNull
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder

interface BindableEnum<T> where T : Enum<T> {
    /**
     * Converts the [BindableEnum] to the [T] enumeration.
     */
    fun toEnum(): T

    /**
     * Converts the [BindableEnum] to the [T] enumeration, or null if the conversion is not possible.
     */
    fun toEnumOrNull(): T?
}


@Serializable(with = StringEnumSerializer::class)
class StringEnum<T> @PublishedApi internal constructor(
    private val value: String,
    private val serializer: KSerializer<T>
) : BindableEnum<T> where T : Enum<T> {
    override fun toEnum(): T = value.decode(serializer)
    override fun toEnumOrNull(): T? = value.decodeOrNull(serializer)
    override fun toString(): String = value
}



class StringEnumSerializer<T>(private val enumSerializer: KSerializer<T>) : KSerializer<StringEnum<T>> where T : Enum<T> {
    override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor(StringEnum::class.qualifiedName!!, PrimitiveKind.STRING)

    override fun deserialize(decoder: Decoder): StringEnum<T> = StringEnum(decoder.decodeString(), enumSerializer)

    override fun serialize(encoder: Encoder, value: StringEnum<T>) {
        encoder.encodeString(value.toString())
    }
}